from rest_framework import serializers
from orders.models import OrdersModel, OrdersDetailModel
from django_redis import get_redis_connection
from coupon.models import CouponLogModel
from django.db import transaction
import datetime
from course.models import CourseModel
from fuguang.utils import constants
import traceback


class OrderModelSerializer(serializers.ModelSerializer):
    user_coupon_id = serializers.IntegerField(write_only=True, default=None)
    class Meta:
        model = OrdersModel
        fields = ['id', 'pay_type', 'credit', 'user_coupon_id']
        extra_kwargs = {
            'pay_type': {'write_only': True},
            'credit': {'write_only': True}
        }

    # 新增数据
    def create(self, validated_data):
        # 往订单表中添加新订单
        # 获取用户，上下文context 获取
        user = self.context['request'].user
        user_id = user.id
        # 获取当前用户的下单商品，获取购物车的redis链接对象
        redis = get_redis_connection('cart')
        # 根据用户id获取当前用户所有购物车数据
        cart_hash = redis.hgetall(f'cart_{user_id}')
        # 判断购物车是否存在商品
        if len(cart_hash) < 1:
            raise serializers.ValidationError(detail='购物车中没有商品', code='cart_empty')

        # 选择兑换积分， 用户所使用积分
        user_credit = int(validated_data.get('credit', 0))

        # 判断用户选择积分，是否超过自身拥有的积分
        if user_credit > 0 and user_credit > user.credit:
            raise serializers.ValidationError(detail='您本次积分不够划扣', code='credit_error')

        # 优惠劵 获取用户使用的优惠劵
        user_coupon_id = validated_data.get('user_coupon_id', None)
        user_coupon1 = None
        if user_coupon_id is not None:
            user_coupon1 = CouponLogModel.objects.filter(id=user_coupon_id, user_id=user_id).first()

        # 创建订单操作   开启数据库事务
        with transaction.atomic():
            # 创建事务的还原点
            t1 = transaction.savepoint()
            try:
                orders = OrdersModel.objects.create(
                    name='浮光商城购买下单',
                    user_id=user_id,
                    # 生成订单号                                                                        会导致位数不一致
                    order_number=datetime.datetime.now().strftime('%Y%m%d') + str('%08d' % user_id) + '%08d' % redis.incr('order_number'),
                    pay_type=validated_data.get('pay_type')
                )
                # 订单记录表创建完成，获取课程，生成订单详情数据，并外键增加
                # 获取到课程列表情况下，通过循环课程列表，计算课程可用积分
                # 获取最优的优惠劵
                # 订单总价   优惠活动以后的总价
                # 课程总价：实付金额

                # 获取选中的课程
                course_id_list = [int(key.decode()) for key, value in cart_hash.items() if value == b'1']
                # 获取购物车中勾选商品的详细商品数据
                course_list = CourseModel.objects.filter(id__in=course_id_list, is_deleted=False, is_show=True)
                # 订单总价
                total_price = 0  # 本次下单总价
                real_price = 0  # 计算优惠活动的价格，循环计算  总价

                # max_user_credit = 0  # 积分  计算最多可以抵扣的积分

                # 最终折扣价格
                total_discount_price = 0  # 最终折扣价格

                # 最优惠的课程
                max_discount_course = None

                # 积分 计算最多可以抵扣的积分
                max_use_credit = 0

                # 循环下单课程信息，需要将下单课程添加到详情表中
                detail_list = []
                for course in course_list:
                    # 获取当前课程的优惠价格，如果没有，则赋值当前原价
                    discount_price = course.discount.get('price', course.price)
                    discount_name = course.discount.get('type', '')

                    # 计算总价  --- 类型转换的报错
                    total_price += course.price
                    # 计算优惠总价
                    real_price = float(real_price) + float(discount_price)

                    detail_list.append(OrdersDetailModel(
                        order=orders,
                        course=course,
                        price=course.price,
                        real_price=discount_price,
                        discount_name=discount_name
                    ))
                    # 找到最优惠的优惠劵
                    if user_coupon_id:
                        if max_discount_course is None:
                            max_discount_course = course
                        else:
                            # 循环当前课程的价格，判断是否已经存在的最优课程的最优惠价格
                            if course.price >= max_discount_course.price:
                                max_discount_course = course

                    if user_credit > 0 and course.credit > 0:
                        # 循环课程获取最大可以使用积分
                        max_use_credit += course.credit
                # 一次性往数据库添加商品详情列表对象
                OrdersDetailModel.objects.bulk_create(detail_list)

                # 计算最终优惠价格
                if user_coupon1:
                    # 获取当前用户选择优惠劵，获取id   -100  *0.8
                    sale = user_coupon1.coupon.sale[1:]
                    if user_coupon1.coupon.discount == 1:
                        # 减免  ---   类型转换错误   最终优惠价格
                        total_discount_price = float(sale)
                        # total_discount_price = real_price - float(sale)
                    elif user_coupon1.coupon.discount == 2:
                        # 类型转换问题，报错
                        total_discount_price = max_discount_course.price * (1-float(sale))

                # 积分
                if user_credit > 0:
                    if max_use_credit < user_credit:
                        raise serializers.ValidationError(detail='超过当前最大可用积分限制', code='credit_max')

                    # 给当前订单，赋值，赋使用的积分
                    orders.credit = user_credit
                    # 把积分按公式换算成钱
                    total_discount_price = float(user_credit/constants.CREDIT_TO_MONEY)
                    # 扣除用户积分  用户当前拥有积分，减去本次下单使用积分
                    user.credit = user.credit - user_credit
                    user.save()

                # 给订单赋值，课程总价，实际付款金额
                orders.total_price = total_price
                # 实际付款金额
                orders.real_price = float(real_price) - total_discount_price
                orders.save()

                # 购物车数据，需要删除
                cart = {key: value for key, value in cart_hash.items() if value == b'0'}
                pipe = redis.pipeline()
                pipe.multi()
                pipe.delete(f'cart_{user_id}')
                if len(cart) > 0:
                    pipe.hset(f'cart_{user_id}', mapping=cart)
                pipe.execute()
                # 优惠劵删除
                if user_coupon1:
                    # 将优惠劵从redis中删除
                    # 将优惠劵信息，绑定到订单中
                    user_coupon1.order = orders
                    user_coupon1.save()
                    redis = get_redis_connection('coupon')
                    redis.delete(f'{user_id}:{user_coupon_id}')
                return orders
            except Exception as ex:
                print('当前订单生成失败......')
                print(ex)
                # 打印异常的类型和描述
                print(f"An error occurred: {type(ex).__name__} - {ex}")
                # 打印异常的完整堆栈信息
                traceback.print_exc()
                # 事务回滚
                transaction.savepoint_rollback(t1)
                raise serializers.ValidationError(detail='订单生成失败，请稍后再试...', code='order_error')


class OrderDetailModelSerializer(serializers.ModelSerializer):
    course_id = serializers.IntegerField(source="course.id")
    course_name = serializers.CharField(source="course.name")
    course_cover = serializers.ImageField(source="course.course_cover")

    class Meta:
        model = OrdersDetailModel
        fields = ['id', 'price', 'real_price', 'discount_name', 'course_id', 'course_name', 'course_cover']


class OrderListModelSerializer(serializers.ModelSerializer):
    order_detail = OrderDetailModelSerializer(many=True)

    class Meta:
        model = OrdersModel
        fields = ['id', 'total_price', 'real_price', 'order_number', 'order_status', 'pay_type', 'order_desc', 'pay_time', 'credit', 'coupon', 'order_detail', 'created_time']
